/**
 * 
 */
package org.extdev.protocol.unsigned;

/**
 * @author LAP
 *
 */
public class UnsignedShort {
	private static final short SHORT_SIGN_CEEPER = 0x4000;
	private static final byte SHORT_SIGN_POSITION = 15;
	private static final byte SHORT_MAX_BIT_NO = 15;
	private static final byte SHORT_MIN_BIT_NO = 0;
	private static final byte LOW_BYTE_POSITION = 0;
	private static final byte HIGH_BYTE_POSITION = 1;
	private static final byte RIGHT_BIT_NUMBER = 1;
	
	private short data;
	
	public UnsignedShort() {
		this((short) 0);
	}
	
	public UnsignedShort(short data) {
		setShort(data);
	}
	
	public UnsignedShort setShort(short data) {
		this.data = data;
		return this;
	}
	
	public boolean getBitValue(int position) {
		if(position > SHORT_MAX_BIT_NO || position < SHORT_MIN_BIT_NO) 
			throw new IllegalArgumentException("Position must be in short range");
		short b = (short) (1 << position);
		return (data & b) == b;
	}
	
	public UnsignedByte getByte(int position) {
		if(position > HIGH_BYTE_POSITION || position < LOW_BYTE_POSITION) 
			throw new IllegalArgumentException("Position must be in short range");		
		short sh = (short) (0xff << position);
		sh &= data;
		short shD = data;
		data = sh;
		unsignedRightShift(position);
		sh = data;
		data = shD;
		return new UnsignedByte((byte)sh);
	}
	
	public short getShort() {
		return data;
	}
	
	public UnsignedShort rotateRight(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			for(int i = 0; i < count; i++) {
				boolean isLastBit = getBitValue(SHORT_MIN_BIT_NO);
				unsignedRightShift(1);
				if(isLastBit) {
					data |= Short.MIN_VALUE;
				}
			}
		}
		return this; 
	}
	
	public UnsignedShort rotateLeft(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			for(int i = 0; i < count; i++) {
				boolean isSigned = getBitValue(SHORT_SIGN_POSITION);
				leftShift(1);
				if(isSigned) {
					data |= RIGHT_BIT_NUMBER;
				}
			}
		}
		return this;
	}
	
	public UnsignedShort unsignedRightShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			boolean sign = getBitValue(SHORT_SIGN_POSITION);
			short signCeeper = 0;
			if(sign) {
				data &= 0x7fff;
				signCeeper = (short) (SHORT_SIGN_CEEPER >>> (count - 1));
			}
			data >>>= count;
			data |= signCeeper;
		}
		return this;
	}
	
	public UnsignedShort leftShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			data <<= count;
		}
		return this;
	}
	
	public UnsignedShort rightShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			data >>= count;
		}
		return this;
	}

	public UnsignedShort xor(short b) {
		data ^= b;
		return this;
	}
	
	public UnsignedShort or(short b) {
		data |= b;
		return this;
	}
	
	public UnsignedShort and(short b) {
		data &= b;
		return this;
	}
}
